/*
 * InputManager.cpp
 *
 *  Created on: 18.11.2009
 *      Author: Sergej Schmidt
 */

#include "InputManager.h"

InputManager *InputManager::m_pInputManager=NULL;

InputManager::InputManager(void) : m_pKeyboard(0), m_pMouse(0), m_pInputSystem(0)
{
}

InputManager::~InputManager()
{
	if( m_pInputSystem )
	{
		if( m_pMouse )
		{
			m_pInputSystem->destroyInputObject( m_pMouse );
			m_pMouse = 0;
		}
		if( m_pKeyboard )
		{
			m_pInputSystem->destroyInputObject( m_pKeyboard );
			m_pKeyboard = 0;
		}
		if( m_vecJoysticks.size() > 0 )
		{
			itJoystick	  = m_vecJoysticks.begin();
			itJoystickEnd = m_vecJoysticks.end();
			for(; itJoystick != itJoystickEnd; ++itJoystick )
			{
				m_pInputSystem->destroyInputObject( *itJoystick );
			}
			m_vecJoysticks.clear();
		}
		OIS::InputManager::destroyInputSystem( m_pInputSystem );

		m_pInputSystem = 0;

		m_mapKeyListeners.clear();
		m_mapMouseListeners.clear();
		m_mapJoystickListeners.clear();
	}
}

void InputManager::initialise( Ogre::RenderWindow *renderWindow )
{
	if( !m_pInputSystem )
	{
		OIS::ParamList paramList;
		size_t windowHnd = 0;
		std::ostringstream windowHndStr;
		renderWindow->getCustomAttribute( "WINDOW", &windowHnd );
		// Заполняем список параметров
		windowHndStr << windowHnd;
		paramList.insert( std::make_pair( std::string( "WINDOW" ), windowHndStr.str()));

		// Создать систему ввода
		m_pInputSystem = OIS::InputManager::createInputSystem( paramList );

        if (m_pInputSystem->getNumberOfDevices(OIS::OISKeyboard) > 0) {
            m_pKeyboard = static_cast<OIS::Keyboard*>( m_pInputSystem->createInputObject( OIS::OISKeyboard, true ) );
            m_pKeyboard->setEventCallback( this );
        }

        if (m_pInputSystem->getNumberOfDevices(OIS::OISMouse) > 0) {
            m_pMouse = static_cast<OIS::Mouse*>( m_pInputSystem->createInputObject( OIS::OISMouse, true ) );
            m_pMouse->setEventCallback( this );

            // Get window size
            unsigned int width, height, depth;
            int left, top;
            renderWindow->getMetrics( width, height, depth, left, top );

            // Set mouse region
            this->setWindowExtents( width, height );
        }
        if (m_pInputSystem->getNumberOfDevices(OIS::OISJoyStick) > 0) {
            //mJoysticks.resize( mInputSystem->numJoySticks() );
            m_vecJoysticks.resize( m_pInputSystem->getNumberOfDevices(OIS::OISJoyStick) );

            itJoystick    = m_vecJoysticks.begin();
            itJoystickEnd = m_vecJoysticks.end();
            for(; itJoystick != itJoystickEnd; ++itJoystick ) {
                (*itJoystick) = static_cast<OIS::JoyStick*>( m_pInputSystem->createInputObject( OIS::OISJoyStick, true ) );
                (*itJoystick)->setEventCallback( this );
            }
        }

	}
}

void InputManager::capture( void )
{
	if( m_pMouse )
	{
		m_pMouse->capture();
	}
	if( m_pKeyboard )
	{
		m_pKeyboard->capture();
	}
	if( m_vecJoysticks.size() > 0 )
	{
        itJoystick    = m_vecJoysticks.begin();
        itJoystickEnd = m_vecJoysticks.end();
        for(; itJoystick != itJoystickEnd; ++itJoystick )
        {
            (*itJoystick)->capture();
        }
	}
}

void InputManager::addKeyListener( OIS::KeyListener *keyListener, const std::string& instanceName )
{
	if( m_pKeyboard )
	{
		itKeyListener = m_mapKeyListeners.find( instanceName );
		if( itKeyListener == m_mapKeyListeners.end() )
		{
			m_mapKeyListeners[ instanceName ] = keyListener;
		}
		else
		{
			//
		}
	}
}

void InputManager::addMouseListener( OIS::MouseListener *mouseListener, const std::string& instanceName )
{
    if( m_pMouse ) {
        // Check for duplicate items
        itMouseListener = m_mapMouseListeners.find( instanceName );
        if( itMouseListener == m_mapMouseListeners.end() ) {
            m_mapMouseListeners[ instanceName ] = mouseListener;
        }
        else {
            // Duplicate Item
        }
    }

}

void InputManager::addJoystickListener( OIS::JoyStickListener *joystickListener, const std::string& instanceName )
{
    if( m_vecJoysticks.size() > 0 ) {
        // Check for duplicate items
        itJoystickListener = m_mapJoystickListeners.find( instanceName );
        if( itJoystickListener != m_mapJoystickListeners.end() ) {
            m_mapJoystickListeners[ instanceName ] = joystickListener;
        }
        else {
            // Duplicate Item
        }
    }

}

void InputManager::removeKeyListener( const std::string& instanceName )
{
	itKeyListener = m_mapKeyListeners.find( instanceName );
	if( itKeyListener != m_mapKeyListeners.end() )
	{
		m_mapKeyListeners.erase( itKeyListener );
	}
}

void InputManager::removeMouseListener( const std::string& instanceName )
{
	itMouseListener = m_mapMouseListeners.find( instanceName );
	if( itMouseListener != m_mapMouseListeners.end() )
	{
		m_mapMouseListeners.erase( itMouseListener );
	}
}

void InputManager::removeJoystickListener( const std::string& instanceName )
{
    itJoystickListener = m_mapJoystickListeners.find( instanceName );
    if( itJoystickListener != m_mapJoystickListeners.end() ) {
        m_mapJoystickListeners.erase( itJoystickListener );
    }

}

void InputManager::removeKeyListener( OIS::KeyListener *keyListener )
{
    itKeyListener    = m_mapKeyListeners.begin();
    itKeyListenerEnd = m_mapKeyListeners.end();
    for(; itKeyListener != itKeyListenerEnd; ++itKeyListener ) {
        if( itKeyListener->second == keyListener ) {
            m_mapKeyListeners.erase( itKeyListener );
            break;
        }
    }

}

void InputManager::removeMouseListener( OIS::MouseListener *mouseListener )
{
    itMouseListener    = m_mapMouseListeners.begin();
    itMouseListenerEnd = m_mapMouseListeners.end();
    for(; itMouseListener != itMouseListenerEnd; ++itMouseListener ) {
        if( itMouseListener->second == mouseListener ) {
            m_mapMouseListeners.erase( itMouseListener );
            break;
        }
    }

}

void InputManager::removeJoystickListener( OIS::JoyStickListener *joystickListener )
{
    itJoystickListener    = m_mapJoystickListeners.begin();
    itJoystickListenerEnd = m_mapJoystickListeners.end();
    for(; itJoystickListener != itJoystickListenerEnd; ++itJoystickListener ) {
        if( itJoystickListener->second == joystickListener ) {
            m_mapJoystickListeners.erase( itJoystickListener );
            break;
        }
    }

}

void InputManager::removeAllListeners( void )
{
	m_mapKeyListeners.clear();
	m_mapMouseListeners.clear();
	m_mapJoystickListeners.clear();
}

void InputManager::removeAllKeyListeners( void )
{
	m_mapKeyListeners.clear();
}

void InputManager::removeAllMouseListeners( void )
{
	m_mapMouseListeners.clear();
}

void InputManager::removeAllJoystickListeners( void )
{
	m_mapJoystickListeners.clear();
}

void InputManager::setWindowExtents( int width, int height )
{
	// Устанавливает регион мыши
	const OIS::MouseState &mouseState = m_pMouse->getMouseState();
	mouseState.width = width;
	mouseState.height = height;
}

OIS::Mouse* InputManager::getMouse( void )
{
    return m_pMouse;
}

OIS::Keyboard* InputManager::getKeyboard( void )
{
    return m_pKeyboard;
}

OIS::JoyStick* InputManager::getJoystick( unsigned int index )
{
    // Make sure it's a valid index
    if( index < m_vecJoysticks.size() ) {
        return m_vecJoysticks[ index ];
    }

    return 0;
}

int InputManager::getNumOfJoysticks( void ) {
    // Cast to keep compiler happy ^^
    return (int) m_vecJoysticks.size();
}

bool InputManager::keyPressed( const OIS::KeyEvent &e )
{
	itKeyListener		= m_mapKeyListeners.begin();
	itKeyListenerEnd	= m_mapKeyListeners.end();
    for(; itKeyListener != itKeyListenerEnd; ++itKeyListener ) {
        itKeyListener->second->keyPressed( e );
    }
	return true;
}

bool InputManager::keyReleased( const OIS::KeyEvent &e )
{
    itKeyListener    = m_mapKeyListeners.begin();
    itKeyListenerEnd = m_mapKeyListeners.end();
    for(; itKeyListener != itKeyListenerEnd; ++itKeyListener ) {
        itKeyListener->second->keyReleased( e );
    }
	return true;
}
bool InputManager::mouseMoved( const OIS::MouseEvent &e )
{
    itMouseListener    = m_mapMouseListeners.begin();
    itMouseListenerEnd = m_mapMouseListeners.end();
    for(; itMouseListener != itMouseListenerEnd; ++itMouseListener ) {
        itMouseListener->second->mouseMoved( e );
    }
	return true;
}

bool InputManager::mousePressed( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
    itMouseListener    = m_mapMouseListeners.begin();
    itMouseListenerEnd = m_mapMouseListeners.end();
    for(; itMouseListener != itMouseListenerEnd; ++itMouseListener ) {
        itMouseListener->second->mousePressed( e, id );
    }


	return true;
}

bool InputManager::mouseReleased( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
    itMouseListener    = m_mapMouseListeners.begin();
    itMouseListenerEnd = m_mapMouseListeners.end();
    for(; itMouseListener != itMouseListenerEnd; ++itMouseListener ) {
        itMouseListener->second->mouseReleased( e, id );
    }

	return true;
}

bool InputManager::povMoved( const OIS::JoyStickEvent &e, int pov )
{
    itJoystickListener    = m_mapJoystickListeners.begin();
    itJoystickListenerEnd = m_mapJoystickListeners.end();
    for(; itJoystickListener != itJoystickListenerEnd; ++itJoystickListener ) {
        itJoystickListener->second->povMoved( e, pov );
    }
	return true;
}

bool InputManager::axisMoved( const OIS::JoyStickEvent &e, int axis )
{
    itJoystickListener    = m_mapJoystickListeners.begin();
    itJoystickListenerEnd = m_mapJoystickListeners.end();
    for(; itJoystickListener != itJoystickListenerEnd; ++itJoystickListener ) {
        itJoystickListener->second->axisMoved( e, axis );
    }
	return true;
}

bool InputManager::sliderMoved( const OIS::JoyStickEvent &e, int sliderID )
{
    itJoystickListener    = m_mapJoystickListeners.begin();
    itJoystickListenerEnd = m_mapJoystickListeners.end();
    for(; itJoystickListener != itJoystickListenerEnd; ++itJoystickListener ) {
        itJoystickListener->second->sliderMoved( e, sliderID );
    }
	return true;
}

bool InputManager::buttonPressed( const OIS::JoyStickEvent &e, int button )
{
    itJoystickListener    = m_mapJoystickListeners.begin();
    itJoystickListenerEnd = m_mapJoystickListeners.end();
    for(; itJoystickListener != itJoystickListenerEnd; ++itJoystickListener ) {
        itJoystickListener->second->buttonPressed( e, button );
    }
	return true;
}

bool InputManager::buttonReleased( const OIS::JoyStickEvent &e, int button )
{
    itJoystickListener    = m_mapJoystickListeners.begin();
    itJoystickListenerEnd = m_mapJoystickListeners.end();
    for(; itJoystickListener != itJoystickListenerEnd; ++itJoystickListener ) {
        itJoystickListener->second->buttonReleased( e, button );
    }
	return true;
}

InputManager* InputManager::getSingletonPtr( void )
{
	if(!m_pInputManager)
	{
		m_pInputManager = new InputManager();
	}
	return m_pInputManager;
}



